# coding=utf-8
'''
Created on Jun 15, 2009

@license: License: LGPL
@copyright: (c) 2009, dogsing.cn
@author: ant-man
'''

from mocObject import MocObject, MocTypeConvertException, MocRuntimeException
from mocInstance import new_instance

class MocConstant(MocObject):
    '''
    Base class of constant object in MOC
    '''

    TYPE = 'CONSTANT'

    def as_int(self, inst):
        ''' Convert current instance to integer'''
        raise MocTypeConvertException("%s type cannot convert to integer" % self.TYPE)

    def as_float(self, inst):
        ''' Convert current instance to float'''
        raise MocTypeConvertException("%s type cannot convert to float" % self.TYPE)

    def as_bool(self, inst):
        ''' Convert current instance to string'''
        raise MocTypeConvertException("%s type cannot convert to boolean" % self.TYPE)

    def as_string(self, inst):
        ''' Convert current instance to string'''
        raise MocTypeConvertException("%s type cannot convert to string" % self.TYPE)


class MocNone(MocConstant):
    TYPE = "NONE"

    def new_inst(self, value=None):
        return new_instance(self, None)
    
    def as_bool(self, inst):
        return False
    
    def op_LNOT(self, rhs):
        return mocTrue 
    
    def pyval(self, inst):
        return None


class MocComparable(MocConstant):

    TYPE = "NUMBER"

    def op_LT(self, lhs, rhs):
        ret = self._cmp_helper(lhs, rhs) < 0
        return mocTrue if ret else mocFalse

    def op_GT(self, lhs, rhs):
        ret = self._cmp_helper(lhs, rhs) > 0
        return mocTrue if ret else mocFalse

    def op_LE(self, lhs, rhs):
        ret = self._cmp_helper(lhs, rhs) <= 0
        return mocTrue if ret else mocFalse

    def op_GE(self, lhs, rhs):
        ret = self._cmp_helper(lhs, rhs) >= 0
        return mocTrue if ret else mocFalse

    def op_EQ(self, lhs, rhs):
        if not rhs.pyval : return mocFalse
        ret = self._cmp_helper(lhs, rhs) == 0
        return mocTrue if ret else mocFalse

    def op_NE(self, lhs, rhs):
        if not rhs.pyval : return mocTrue
        ret = self._cmp_helper(lhs, rhs) != 0
        return mocTrue if ret else mocFalse
    
    def op_LNOT(self, rhs):
        return mocTrue if not rhs.as_bool() else mocFalse

    def _cmp_helper(self, lhs, rhs):
        raise NotImplementedError()


class MocInt(MocComparable):

    TYPE = "INT"

    def new_inst(self, value=0):
        return new_instance(self, int(value))

    def as_int(self, inst):
        return inst.value

    def as_float(self, inst):
        return float(inst.value)

    def as_bool(self, inst):
        return inst.value > 0

    def as_string(self, inst):
        return str(inst.value)

    def pyval(self, inst):
        return self.as_int(inst)

    def op_PLUS(self, lhs, rhs):
        ret = lhs.as_int() + rhs.as_int()
        return self.new_inst(ret)

    def op_MINUS(self, lhs, rhs):
        ret = lhs.as_int() - rhs.as_int()
        return self.new_inst(ret)

    def op_TIMES(self, lhs, rhs):
        ret = lhs.as_int() * rhs.as_int()
        return self.new_inst(ret)

    def op_DIVIDE(self, lhs, rhs):
        ret = lhs.as_int() / rhs.as_int()
        return self.new_inst(ret)

    def op_MOD(self, lhs, rhs):
        ret = lhs.as_int() % rhs.as_int()
        return self.new_inst(ret)

    def op_OR(self, lhs, rhs):
        ret = lhs.as_int() | rhs.as_int()
        return self.new_inst(ret)

    def op_AND(self, lhs, rhs):
        ret = lhs.as_int() ^ rhs.as_int()
        return self.new_inst(ret)

    def op_XOR(self, lhs, rhs):
        ret = lhs.as_int() + rhs.as_int()
        return self.new_inst(ret)

    def op_LSHIFT(self, lhs, rhs):
        ret = lhs.as_int() << rhs.as_int()
        return self.new_inst(ret)

    def op_RSHIFT(self, lhs, rhs):
        ret = lhs.as_int() >> rhs.as_int()
        return self.new_inst(ret)

    def op_NOT(self, rhs):
        return self.new_inst(~rhs.as_int())

    def op_PREPLUS(self, rhs):
        return self.new_inst(rhs.as_int())

    def op_PREMINUS(self, rhs):
        return self.new_inst(-rhs.as_int())

    def _cmp_helper(self, lhs, rhs):
        if rhs.type_equals(mocFloat) :
            return  lhs.as_float() - rhs.as_float()
        else :
            return lhs.as_int() - rhs.as_int()


class MocFloat(MocComparable):

    TYPE = "FOLAT"

    def new_inst(self, value=0.0):
        return new_instance(self, float(value))

    def as_int(self, inst):
        return int(inst.value)

    def as_float(self, inst):
        return inst.vaule

    def as_bool(self, inst):
        return inst.value > 0.0

    def as_string(self, inst):
        return str(inst.value)

    def pyval(self, inst):
        return self.as_float(inst)

    def op_PLUS(self, lhs, rhs):
        ret = lhs.as_float() + rhs.as_float()
        return self.new_inst(ret)

    def op_MINUS(self, lhs, rhs):
        ret = lhs.as_float() - rhs.as_float()
        return self.new_inst(ret)

    def op_TIMES(self, lhs, rhs):
        ret = lhs.as_float() * rhs.as_float()
        return self.new_inst(ret)

    def op_DIVIDE(self, lhs, rhs):
        ret = lhs.as_float() / rhs.as_float()
        return self.new_inst(ret)

    def op_PREPLUS(self, rhs):
        return self.new_inst(rhs.as_float())

    def op_PREMINUS(self, rhs):
        return self.new_inst(-rhs.as_float())

    def _cmp_helper(self, lhs, rhs):
        return  lhs.as_float() - rhs.as_float()


class MocBool(MocComparable):

    TYPE = "BOOL"

    def new_inst(self, value=True):
        return new_instance(self, bool(value))

    def as_int(self, inst):
        return 1 if inst.value else 0

    def as_bool(self, inst):
        return inst.value

    def as_string(self, inst):
        return str(inst.value)

    def pyval(self, inst):
        return self.as_bool(inst)

    def op_LAND(self, lhs, rhs):
        return mocTrue if lhs.as_bool() and rhs.as_bool() else mocFalse

    def op_LOR(self, lhs, rhs):
        return mocTrue if lhs.as_bool() or rhs.as_bool() else mocFalse

    def _cmp_helper(self, lhs, rhs):
        a = lhs.as_bool()
        b = rhs.as_bool()
        if a == b : return 0
        elif a > b : return 1
        else: return - 1


class MocString(MocComparable):

    TYPE = "STRING"

    def new_inst(self, value=""):
        return new_instance(self, str(value))

    def as_int(self, inst):
        return int(inst.value)

    def as_float(self, inst):
        return float(inst.value)

    def as_bool(self, inst):
        return inst.value != ""

    def as_string(self, inst):
        return eval(inst.value)

    def pyval(self, inst):
        return self.as_string(inst)

    def op_PLUS(self, lhs, rhs):
        return mocString.new_inst(repr(lhs.as_string() + rhs.as_string()))

    def str_len(self, inst):
        return mocInt.new_inst(len(eval(inst.value)))

    def _cmp_helper(self, lhs, rhs):
        a = lhs.as_string()
        b = rhs.as_string()
        if a == b : return 0
        elif a > b : return 1
        else: return - 1


#class MocField(MocObject):
#    """
#    """
#    TYPE = "FIELD"
#
#    def new_inst(self, value):
#        assert isinstance(value, tuple)
#        return new_instance(self, value)

mocNone = MocNone()
mocInt = MocInt()
mocFloat = MocFloat()
mocString = MocString()
mocGNone = mocNone.new_inst()
mocTrue = MocBool().new_inst(True)
mocFalse = MocBool().new_inst(False)
#mocField = MocField()

